#include "temparena.h"

void CopyToMap(TempHash<uint64, uint64> &h, map<uint64, uint64> &m, uint64 range) {
  for (uint64 i=0; i<range; i++) {
    uint64 * v = h.Lookup(i, NULL);
    if (v) {
      m[i] = *v;
    }
  }
}

void AutoTest(TempHash<uint64, uint64> &h, map<uint64, uint64> &m, uint64 reps) {
  for (uint64 rep = 0; rep < reps; rep++) {
    if (rep > 0 && rep % 1000000 == 0) cout << "Testing " << rep << endl;
    uint64 op = rand() % 5;
    if (op == 0) {
      // SET
      uint64 k = rand() % 100;
      uint64 v = rand() % 100;
      h[k] = v;
      m[k] = v;
    }
    if (op == 1) {
      // GET
      uint64 k = rand() % 100;
      uint64 v1 = h[k];
      uint64 v2 = m[k];
      CHECK(v1 == v2);     
    }
    if (op == 2) {
      // %
      uint64 k = rand() % 100;
      uint64 * v1 = h % k;
      uint64 * v2 = m % k;
      CHECK( (v1 == NULL) == (v2 == NULL));
      if (v1) CHECK(*v1 == *v2);
    }
    if (op == 3) {
      // DEL
      uint64 k = rand() % 100;
      m.erase(k);
      h.Delete(k);
    }
  }
}

void AutoTest() {
  map<uint64, uint64> m;
  TempHashArena a;
  a.Init(20, false);
  TempHashArena b;
  b.Init(20, true);
  TempHash<uint64, uint64> h; h.Init(&a, 9);
  AutoTest(h, m, 1000000);
  cout << "Passed base" << endl;
  for (uint64 rep=0; rep<10000; rep++) {
    if (rep % 10 == 0) cout << "testing overlay " << rep << endl; 
    map<uint64, uint64> m2 = m;
    map<uint64, uint64> m3; CopyToMap(h, m3, 100);
    CHECK(m2 == m3);
    b.Clear();
    TempHash<uint64, uint64> h2; h2.Init(&b, 10);
    h2.AddBase(&h);
    AutoTest(h2, m2, 10000);
  }
  cout << "Passed AutoTest" << endl;
}

void explore (TempHash<uint64, uint64> & h) {
  string cmd;
  uint64 n1, n2;
  while (1) {
    cin >> cmd;
    if (cmd == "set") {
      cin >> n1 >> n2;
      h[n1] = n2;
    }
    if (cmd == "get") {
      cin >> n1;
      cout << h[n1] << endl;
    }
    if (cmd == "%") {
      cin >> n1;
      uint64 * look = h % n1;
      cout << (void*) look << endl;
    }
    if (cmd == "del") {
      cin >> n1;
      h.Delete(n1);
    }
    if (cmd == "see") {
      cin >> n1 >> n2;
      for (uint64 i=n1; i<n2; i++) {
	uint64 * look = h % i;
	if (look) {
	  cout << i << "->" << *look << " ";
	}
      }
      cout << endl;
    }
    if (cmd == "inc") {
      cin >> n1 >> n2;
      uint64 old = h[n1];
      h[n1] = old + n2;
    }
    if (cmd == "q") break;
  }
}

int temparena_main() {
  AutoTest();
  TempHashArena a;
  a.Init(20, false);
  TempHash<uint64, uint64> h; h.Init(&a, 9);
  explore(h);
  TempHash<uint64, uint64> h2; h2.Init(&a, 10);
  h2.AddBase(&h);
  explore(h2);
  return 0;
}
